package com.iot08.api.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.tea.utils.StringUtils;
import com.iot08.api.config.properties.ListDataProperties;
import com.iot08.api.response.ChatMessageLastResp;
import com.iot08.api.service.supplement.KafkaService;
import com.iot08.api.utils.ContentSecurityUtil;
import com.iot08.api.utils.buckettool.BaseBucketTool;
import com.iot08.api.utils.request.ParamHandle;
import com.iot08.api.vo.request.*;
import com.iot08.common.constant.Const;
import com.iot08.common.constant.ConstKafka;
import com.iot08.common.entity.app.*;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.CollectionUtil;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.StringUtil;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * 单聊群组
 * @time: 2021-10-30 17:33
 * @author: Weichao
 * @version 1.0
 */
@Slf4j
@Service
public class SingleChatGroupService extends BaseService<SingleChatGroup> {

    @Resource
    private AccountService accountService;
    @Resource
    private DeviceService deviceService;
    @Resource
    private BaseBucketTool baseBucketTool;
    @Resource
    private KafkaService kafkaService;
    @Resource
    private ListDataProperties listDataProperties;
    @Resource
    private SingleChatGroupMessageService singleChatGroupMessageService;

    @Resource
    private ChatGroupService chatGroupService;

    @Resource
    private VipMemberService vipMemberService;

    @Resource
    private ContentSecurityUtil contentSecurityUtil;
    @Resource
    private UserKeyActionService userKeyActionService;

    @Resource
    private SensitivityFileSingleMessageService sensitivityFileSingleMessageService;



    @Value("${domain.name}")
    private String domainName;

    /**
     * 创建单聊群组
     * @param accountId
     * @param imei
     * @time: 2021-10-30 18:08
     * @author: Weichao
     * @version 1.0
     */
    public void createSingleG(String accountId, String imei) {
        SingleChatGroup group = new SingleChatGroup();
        // 单聊 的群组Id 创建的规则:
        // "用户ID" + & + "imei"
        group.setId(accountId+"&"+imei);
        group.setOpenid(accountId);
        group.setImei(imei);
        Double time = DateUtil.nowTimestampToDouble();
        group.setTimestamp(time);
        group.setCreateTime(new Date());
        this.save(group);
    }

    /**
     * 获取聊天群组信息
     *
     * @param groupid
     * @param vo
     * @time: 2021-10-30 18:08
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap getInfo(String groupid, ChatGroupGetInfoReqVO vo) {
        if (StringUtil.isBlank(groupid)) {
            return ResponseMap.fail();
        }
        SingleChatGroup chatGroup = this.findById(groupid);
        if (chatGroup == null) {
            log.error("SingleChatGroup is null. id={}", groupid);
            return ResponseMap.fail();
        }
        JSONArray memberList = new JSONArray();

        Map<String, Object> m = new HashMap<>();
        m.put("openid", chatGroup.getOpenid());
        memberList.add(m);

        JSONArray deviceList = new JSONArray();
        Map<String, Object> d = new HashMap<>();
        d.put("imei", chatGroup.getImei());
        deviceList.add(d);

        ResponseMap res = ResponseMap.success();
        res.put("groupid", chatGroup.getId());
        res.put("groupType", vo.getGroupType());
        res.put("creator", chatGroup.getOpenid());
        res.put("members", memberList);
        res.put("devices", deviceList);
        res.put("avator", "");
        res.put("name", "");
        //当前查询的用户
        Document document = accountService.findDocById(vo.getOpenid());
        if (document != null && document.get(chatGroup.getId()) != null) {
            res.put("msgNum", document.get(chatGroup.getId()));
        } else {
            res.put("msgNum", 0);
        }
        //log.info(" chatGroup openid = {}. groupid = {}. msgNum = {}", vo.getOpenid(), groupid, res.get("msgNum"));
        res.put("groupType", vo.getGroupType());
        return res;
    }

    /**
     * 发送聊天群聊天消息
     *
     * @param groupid
     * @param openid
     * @param type
     * @param duration
     * @param imei
     * @param content
     * @param bqId
     * @time: 2021/3/6 17:50
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap sendMessage(String groupid, String openid, Integer type, Double duration, String imei, Object content) throws IOException {
        Account account = accountService.findById(openid);
        if (account == null) {
            log.error("Account is null. id={}, aid={}. ", groupid, openid);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        SingleChatGroup chatGroup = this.findById(groupid);
        if (chatGroup == null) {
            log.error("SingleChatGroup is null. id={}, aid={} ", groupid, openid);
            return ResponseMap.fail(ResponseEnum.STATUS2003.getCode(), ResponseEnum.STATUS2003.getMsg());
        }
        SingleChatGroupMessage message = new SingleChatGroupMessage();
        message.setGroupid(groupid);
        message.setSender(openid);
        message.setAvator(baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH
                + (StringUtil.isBlank(account.getImage()) ? Const.DEFAULT_JPG : account.getImage()));
        message.setMessageType(type);
        message.setSendType(1);
        message.setIsExceedLimitRecord(1);
        //下发语音消息生成日期
        message.setChatReportTime(DateUtil.stampToDateStr(System.currentTimeMillis(),DateUtil.FORMAT_1));
        //
        JSONObject subJson = new JSONObject();
        Object relationship = "爸爸";
        Object relationshipImageId = 1;
        Device device = deviceService.findById(chatGroup.getImei());
        if (device != null && CollectionUtil.containsKey(device.getUserMap(), openid)) {
            relationship = device.getUserMap().get(openid).get("relationship");
            relationshipImageId = device.getUserMap().get(openid).get("relationship_image_id");
            if (StringUtil.isNotBlank(relationship)) {
                message.setRelationship(relationship.toString());
                subJson.put("relationship", message.getRelationship());
            }
            if (StringUtil.isNumeric(relationshipImageId)) {
                message.setRelationshipImageId(Integer.parseInt(relationshipImageId.toString()));
                subJson.put("relationship_image_id", message.getRelationshipImageId());
            }
            message.setOpenid(openid);
            subJson.put("openid", openid);
        }
        if (Const.INT_1.equals(type) && content instanceof String) {
            //文字消息
            message.setContent((String) content);
            subJson.put("content", message.getContent());
        } else if (new Integer(2).equals(type) && content instanceof MultipartFile) {
            MultipartFile file = (MultipartFile) content;
            //图片消息
            if (file.isEmpty()) {
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.sendErrorTry");
            }
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToJpg();
            //上传文件
            baseBucketTool.upload(BaseBucketTool.MESSAGE_COMMON_PATH + fileName, file, 1);
            message.setSize(file.getSize());
            message.setContent(fileName);
            subJson.put("content", baseBucketTool.getDOMAIN() + BaseBucketTool.MESSAGE_COMMON_PATH + fileName);
        } else if (new Integer(3).equals(type) && content instanceof MultipartFile) {
            //语音
            MultipartFile file = (MultipartFile) content;
            if (file.isEmpty() || StringUtil.isBlank(type)) {
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.sendErrorTry");
            }
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileName(file, "amr");
            baseBucketTool.upload(BaseBucketTool.MESSAGE_COMMON_PATH + fileName, file, 2);
            message.setSize(file.getSize());
            message.setDuration(duration);
            message.setContent(fileName);
            subJson.put("content", baseBucketTool.getDOMAIN() + BaseBucketTool.MESSAGE_COMMON_PATH + fileName);
            subJson.put("duration", duration > 1 ? duration : 1);
        } else if (type == 4) {
            //表情包
            message.setContent(content.toString());
            message.setBqId(content.toString());
            subJson.put("bqId", content.toString());
        } else {
            return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "params type is invalid " + type);
        }
        subJson.put("id", message.getId());
        subJson.put("groupType", 1);
        subJson.put("senderID", message.getSender());
        subJson.put("senderType", message.getSendType());
        subJson.put("type", message.getMessageType());
        Double timestamp = message.getTimestamp();
        Long timestampLong ;
        if(timestamp == null){
            timestampLong = DateUtil.nowTimestampToLong();
        }else{
            timestampLong = timestamp.longValue();
        }
        subJson.put("timestamp", timestampLong);
        //发送kafka
        //JSONObject pushData = new JSONObject();
        //pushData.put("type", ConstKafka.CHAT_GROUP_MESSAGE);
        //pushData.put("groupid", groupid);
        //pushData.put("message", subJson);
        //发送推送到 APP 单聊 APP发送的 不需要再推一次
//        kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_1, groupid, pushData);
        //下发到设备的 指令
        JSONObject json = new JSONObject();
        String devType = ConstKafka.DEVICE_TYPE_DownChatVoice;
        json.put("groupId", groupid);
        json.put("groupType", 0);
        json.put("contentType", message.getMessageType());
        json.put("timestamp", timestampLong);
        //附带上和手表的关系
        json.put("relationship_image_id",relationshipImageId);
        json.put("relationship",relationship);
        if (Const.INT_1.equals(message.getMessageType())) {
            //文字
            //TODO: 判断设备是 ASR设备, 如果文字超过 230个字节,直接截断到230个
            String contentStr = message.getContent();
            if(device != null && "ASR".equalsIgnoreCase(device.getPlatform())){
                int maxByteLen = 230;
                if (contentStr.getBytes().length > maxByteLen) {
                    return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.sendMsgErrorTooLong");
//                log.info("发送设备imei:{} 的文字信息 38 指令的内容超过 {} 个字节,截取内容到限制长度再发送到设备", imei, maxByteLen);
//                byte[] bs = new byte[maxByteLen];
//                System.arraycopy(contentStr.getBytes(), 0, bs, 0, maxByteLen);
//                contentStr = new String(bs, "UTF-8");
                }
            }
            //文字消息
            //检测敏感词====
            boolean res = contentSecurityUtil.chatTextAudit(contentStr, openid);
            if(!res){
                //聊天内容包含敏感词汇
                userKeyActionService.add(10,openid, "用户微聊: 敏感词违规 内容:"+content);
                //保存敏感信息
                sensitivityFileSingleMessageService.saveData(groupid,message);
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "聊天内容包含敏感词汇");
            }
            json.put("content", contentStr);
            //devType = ConstKafka.DEVICE_TYPE_ChatMessage;
            json.put("type",ConstKafka.DEVICE_TYPE_ChatMessage);
        } else if (new Integer(2).equals(message.getMessageType()) ){
            //图片
            json.put("id", message.getId());
            json.put("photoUrl", baseBucketTool.getDOMAIN() + BaseBucketTool.MESSAGE_COMMON_PATH + message.getContent());
            //在OSS 上面的文件路径
            json.put("photoPath", "/"+BaseBucketTool.MESSAGE_COMMON_PATH + message.getContent());
            json.put("size", message.getSize() == null ? 0 : message.getSize());
            json.put("type", ConstKafka.DEVICE_TYPE_DownChatVoice);
        } else if (new Integer(3).equals(message.getMessageType())) {
            //语音
            json.put("url", baseBucketTool.getDOMAIN() + BaseBucketTool.MESSAGE_COMMON_PATH + message.getContent());
            json.put("duration", message.getDuration() == null ? 0 : message.getDuration().intValue());
            json.put("size", message.getSize() == null ? 0 : message.getSize());
            json.put("id", message.getId());
            json.put("voiceUrl", baseBucketTool.getDOMAIN() + BaseBucketTool.MESSAGE_COMMON_PATH + message.getContent());
            //在OSS 上面的文件路径
            json.put("voicePath", "/"+BaseBucketTool.MESSAGE_COMMON_PATH + message.getContent());
            message.getDuration().intValue();
            json.put("duration", message.getDuration() == null ? 0 : message.getDuration().intValue()+1);
            json.put("size", message.getSize() == null ? 0 : message.getSize());
            json.put("type", ConstKafka.DEVICE_TYPE_DownChatVoice);
        } else if (new Integer(4).equals(message.getMessageType())) {
            //表情
            // json.put("bqId", bqId);
            json.put("content",content.toString());
            json.put("type",ConstKafka.DEVICE_TYPE_ChatMessage) ;
        }
        if (new Integer(3).equals(type)) {
            //检测敏感词-语音====
            if(!contentSecurityUtil.chatAudioAudit(subJson.getString("content") ,openid,groupid,message.getId())) {
                log.error("发送微聊的语音信息包含敏感信息，无法发送，出现敏感信息的设备为:{},所属群组为：{},发送的用户为：{}",imei,groupid,openid);
                //保存敏感信息
                sensitivityFileSingleMessageService.saveData(groupid,message);
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "发送语音包含敏感信息");
            }
        } else if(new Integer(2).equals(type)) {
            if(!ContentSecurityUtil.imageAudit(subJson.getString("content"),openid)){
                log.error("发送微聊的图片信息包含敏感信息，无法发送，出现敏感信息的设备为:{},所属群组为：{},发送的用户为：{}",imei,groupid,openid);
                //保存敏感信息
                sensitivityFileSingleMessageService.saveData(groupid,message);
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "发送图片包含敏感信息");
            }
        }
        //保存消息
        singleChatGroupMessageService.add(message);
        json.put("id", message.getId());
        if(!StringUtils.isEmpty(imei)) {
            //json = chatGroupService.assembleNewWechatData(type,imei,json,account.getPhone(),"0");
            json = chatGroupService.assemblyNewWechatData(type,imei,json,account.getId(),"0");
            kafkaService.emitDeviceDemand(imei, json.getString("type"), json, openid);
        }
        //APP 发送的不用标记未读
//        //更新下未读消息 因为单聊的只有一个,所以APP的未读消息记录在这个 singleChatGroup 上
//        Integer bage = chatGroup.getBage();
//        chatGroup.setBage(++bage);
//        this.save(chatGroup);
        ResponseMap res = ResponseMap.success();
        res.put("id", message.getId());
        res.put("content", subJson.get("content"));
        return res;
    }



    /**
     * 获取单聊聊天群聊天消息
     *
     * @param groupid
     * @param vo
     * @time: 2021/1/14 11:40
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getMessage(String groupid, ChatGroupGetMessageReqVO vo, HttpServletRequest request) {
        Account account = accountService.findById(vo.getOpenid());
        if (account == null) {
            log.error("Account is null. id={}. getMessage vo={}", vo.getOpenid(), vo);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }

        //更新下未读消息 因为单聊的只有一个,所以APP的未读消息记录在这个 singleChatGroup 上 ,调用了 获取聊天消息接口 证明,进入到微聊页面了, 取消未读数
        SingleChatGroup chatGroup = this.findById(groupid);
        chatGroup.setBage(0);
        chatGroup.setNoVipBage(0);
        this.save(chatGroup);

        Double deletetime = chatGroup.getDeletetime();

        ResponseMap res = ResponseMap.success();
        Document query = new Document();
        //参数query处理
        ParamHandle.queryParamHandle(query, vo.getQuery());
        query.put("i", groupid);
        //检查用户是否是会员，不是会员时发送消息的内容是否超过限制，会员可以查看超过限制的记录，非会员则只能看没有超过限制的记录
        VipMember vipMember = vipMemberService.queryVipMemberByOpenid(vo.getOpenid());
        if(ObjectUtils.isEmpty(vipMember)){
            query.put("isExceedLimitRecord",1);
        }
        if (deletetime != null) {
            Document tempQ = new Document();
            String otherQStr = "{\"t\":{\"$gt\":"+deletetime+"}}";
            tempQ.append("$and", Arrays.asList(query,JSONObject.parseObject(otherQStr)));
            query = tempQ;
            log.info("单聊查询聊天消息的 查询条件:{}", query);
        }else{
            //deletetime == nil 使用 群里创建时的时间
            deletetime = chatGroup.getTimestamp();
        }
        //判断是否是 iOS + 微信
        boolean isWX_ios = checkIsWX_IOS(request);
        res.put("messages", singleChatGroupMessageService.messageQueryHandle(deletetime, query, vo.getNum(), vo.getPage(), vo.getSort(), isWX_ios));
        return res;
    }

    /**
     * @description 查询最后一条微聊记录
     * @author cwj
     * @param [groupid, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/7/1 10:44
     **/
    public ResponseMap getLastMessage(String groupid,String openid){
        Account account = accountService.findById(openid);
        if (ObjectUtils.isEmpty(account)) {
            log.error("Account is null. id={}", openid);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        SingleChatGroup singleChatGroup = this.findById(groupid);
        if (ObjectUtils.isEmpty(singleChatGroup)) {
            log.error("SingleChatGroup is null. id={}", groupid);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        Double deletetime = singleChatGroup.getDeletetime();
        if(ObjectUtils.isEmpty(deletetime)) {
            deletetime = singleChatGroup.getTimestamp();
        }
        ChatMessageLastResp chatMessageLastResp = singleChatGroupMessageService.queryLastMessage(groupid,openid,deletetime);
        ResponseMap res = ResponseMap.success();
        res.put("chatMessageLastResp",ObjectUtils.isEmpty(chatMessageLastResp)?new ChatMessageLastResp():chatMessageLastResp);
        return res;
    }

    /**
     * 清空 单聊 聊天群聊天消息
     *
     * @param groupid
     * @param vo
     * @time: 2021/2/22 10:05
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delMessage(String groupid, ChatGroupDelAccountReqVO vo) {
        Account account = accountService.findById(vo.getOpenid());
        if (account == null) {
            log.error("Account is null. id={}. delMessage vo={}", vo.getOpenid(), vo);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        SingleChatGroup chatGroup = this.findById(groupid);
        chatGroup.setBage(0);
        chatGroup.setDeletemsgid(vo.getDeletemsgid());
        chatGroup.setDeletetime(DateUtil.nowTimestampToDouble());
        this.save(chatGroup);
        return ResponseMap.success();
    }

    public void delByImei(String imei){
        this.delByQuery(new Query(Criteria.where("imei").is(imei)));
    }

    public List<SingleChatGroup> findByImei(String imei){
        return this.find(new Query(Criteria.where("imei").is(imei)));
    }

    public SingleChatGroup findByImeiAndOpenid(String imei, String openid){
        return this.findOne(new Query(Criteria.where("imei").is(imei).and("openid").is(openid)));
    }

    public boolean checkIsWX_IOS(HttpServletRequest req){
        /*

            # 安卓手机, 微信小程序 请求头
            user-agent : Mozilla/5.0 (Linux; Android 14; 23113RKC6C Build/UKQ1.230804.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 XWEB/1160083 MMWEBSDK/20231202 MMWEBID/8242 MicroMessenger/8.0.47.2560(0x28002F51) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android

            # iOS手机, 微信小程序 请求头
            user-agent : Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.37(0x1800252f) NetType/WIFI Language/zh_CN

            */


        //判断是否 iOS + 微信小程序
        //获取不区分大小写, 统一小写
        String userAgent = req.getHeader("user-agent");
        boolean isWX_IOS = false;
        if(userAgent.contains("MicroMessenger")){
            log.info("识别为 微信 (目前无法分辨到小程序)  userAgent:{}", userAgent);
            isWX_IOS = true;
            return isWX_IOS;
        }
//        if(userAgent.contains("iPhone") && userAgent.contains("MicroMessenger")){
//            log.info("识别为 iOS + 微信 (目前无法分辨到小程序)  userAgent:{}", userAgent);
//            //iOS + 微信 (目前无法分辨到小程序)
//            isWX_IOS = true;
//        }
        return isWX_IOS;
    }

}
